package utils

import (
	"errors"
	"os"
	"reflect"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
)

// 返回数据
func ReturnJson(ctx *gin.Context, code int, data any, err error) {
	msg := ""
	switch code {
	case 0:
		msg = "success"
	default:
		if err == nil {
			err = errors.New("请求错误")
		}
		msg = err.Error()
	}
	out := map[string]any{
		"code": code,
		"msg":  msg,
		"data": data,
	}
	ctx.JSONP(200, out)
}

// 查看数组内是否有
func ArrayFindString(search []string, flag string) bool {
	for _, v := range search {
		if v == flag {
			return true
		}
	}
	return false
}

// 往下查找msg
func findTagMsg(getObj reflect.Type, keyName string, msg *string) {
	switch getObj.Kind() {
	case reflect.Ptr:
		// 指针类型
		getObj = getObj.Elem()
	case reflect.Slice:
		// 切片类型
		getObj = getObj.Elem()
	default:
		_ = 1
	}
	// 非结构体类型，直接返回
	if getObj.Kind() != reflect.Struct {
		return
	}
	f, exist := getObj.FieldByName(keyName)
	if exist {
		*msg = f.Tag.Get("msg")
		return
	}
	// 没有找到继续，向下查找
	for i := 0; i < getObj.NumField(); i++ {
		findTagMsg(getObj.Field(i).Type, keyName, msg)
	}
}

// 绑定参数，利用的gin的bind逻辑，可返回自定义错误
// 优化 支持嵌套结构体往下查找
func FbindParams(ctx *gin.Context, input interface{}) error {
	if err := ctx.ShouldBind(input); err != nil {
		// 通过反射返回错误
		errMsg := err.Error()
		getObj := reflect.TypeOf(input)
		if errs, ok := err.(validator.ValidationErrors); ok {
			for _, e := range errs {
				msg := ""
				findTagMsg(getObj, e.Field(), &msg)
				if msg != "" {
					errMsg = msg
					break
				}
			}
		}
		return errors.New(errMsg)
	}
	return nil
}

// 查看目录是否存在
func FileOrDirExists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		return os.IsExist(err)
	}
	return true
}

// 创建目录
func MakeDirAll(path string) error {
	if FileOrDirExists(path) {
		return nil
	}
	return os.MkdirAll(path, os.ModePerm)
}

// 指定数组元素删除,step表示要删除的位置，-1表示末尾
func DelArrItemStr(arr []string, step int) []string {
	endStep, arrLen := step, len(arr)
	if step < 0 {
		endStep = arrLen + step
	}
	arr = append(arr[:endStep], arr[endStep+1:]...)
	return arr
}